home *** CD-ROM | disk | FTP | other *** search
- /*
- * MICRO BASIC:
- *
- * This is a very simple INTEGER BASIC interpreter that I wrote a number of
- * years ago, and subsequently ported to MICRO-C. While not the greatest
- * example of coding style (it was a quick and dirty hack job), It is quite
- * instructive, as a simple but fairly complete interpreter.
- *
- * Variables:
- * 260 Numeric variables: A0-A9 ... Z0-Z9
- * 260 Character variables: A0$-A9$ ... Z0$-Z9$
- *
- * NOTE: For convenience the '0' variables can be referenced by letter
- * only. IE: A is equivalent to A0 ... Z$ is equivalent to Z0$
- *
- * Statements:
- * LET (default) - variable = expression
- * EXIT - Terminate MICRO-BASIC
- * LIST [start,[end]] - List program lines
- * LIST#n ... - List program to file (0-9)
- * NEW - Erase program and variables
- * RUN [line] - Run program
- * CLEAR - Erase variables only
- * GOSUB line - Call a subroutine
- * GOTO line - Jump to line
- * RETURN - Return from subroutine
- * PRINT expr[,expr ...] - Print to console
- * PRINT#n ... - Print to file (0-9)
- * FOR v=init TO limit [STEP increment] - Perform a counted loop
- * NEXT [v] - End counted loop
- * IF test THEN line - Conditional goto
- * IF test THEN statement - Conditional statement (next statement only)
- * LIF test THEN statements- LONG IF (all statements to end of line)
- * REM - Comment... reminder of line is ignored
- * STOP - Terminate program & issue message
- * END - Terminate program with no message
- * INPUT var - Get value for variable
- * INPUT "prompt",var - Get value of variable with prompt
- * NOTE: prompt must be a constant string, however you can use
- * a char variable in prompt by concatinating it to such
- * a string: INPUT ""+a$,b$
- * INPUT#n,var - Get value for variable from file (0-9)
- * OPEN#n,"name","opts" - Open file (0-9), opts are same as "fopen()"
- * CLOSE#n - Close file (0-9)
- *
- * Operators:
- * + - Addition, string concatination
- * - - Unary minus, subtraction
- * *, /, %, - multiplication, division, modulus
- * &, |, ^ - AND, OR, Exclusive OR
- * =, <> - Assignment/test equal, test NOTequal (num or string)
- * <, <=, >, >= - LT, LE, GT, GE (numbers only)
- * ! - Unary NOT
- *
- * Functions:
- * CHR$(value) - Returns character of passed value
- * STR$(value) - Returns ASCII string of value's digits
- * ASC(char) - Returns value of passed character
- * ABS(value) - Returns absolute value of argument
- *
- * If want to use a different compiler, take note:
- *
- * - Make sure 'fgets' does not include the trailing NEWLINE
- * You can use "microc.h" from utilities source directory.
- *
- * - Make sure that 'isalpha' and 'isdigit' can deal with negative
- * character values (most macro implementations can't). If not,
- * include those functions from the MICRO-C library.
- *
- * - Modify the declaration of 'savjmp' to whatever is appropriate
- * for your compilers 'setjmp' and 'longjmp' functions.
- *
- * Copyright 1982-1994 Dave Dunfield
- * All rights reserved.
- *
- * Permission granted for personal (non-commercial) use only.
- *
- * Compile command: cc basic -fop
- */
- #include <stdio.h>
-
- /* Fixed parameters */
- #define BUFFER_SIZE 100 /* input buffer size */
- #define NUM_VAR 260 /* number of variables */
- #define SA_SIZE 100 /* string accumulator size */
-
- /* Reserved word grouping */
- #define SEC 21 /* secondary keywords */
- #define OPS SEC+3 /* first operator */
- #define SOPS OPS+14 /* first string function */
- #define NOPS SOPS+2 /* first numeric function */
-
- /* Control stack constant identifiers */
- #define FOR 1000 /* indicate FOR statement */
- #define GOSUB FOR+1 /* indicate GOSUB statement */
-
- struct line_record {
- unsigned Lnumber;
- struct line_record *Llink;
- char Ltext[]; };
-
- static char *reserved_words[] = {
- "LET", "EXIT", "LIST", "NEW", "RUN", "CLEAR", "GOSUB", "GOTO",
- "RETURN", "PRINT", "FOR", "NEXT", "IF", "LIF", "REM", "STOP",
- "END", "INPUT", "OPEN", "CLOSE", "TO", "STEP", "THEN",
- "+", "-", "*", "/", "%", "&", "|", "^",
- "=", "<>", "<=", "<", ">=", ">",
- "CHR$(", "STR$(", "ASC(", "ABS(",
- 0 };
-
- static char priority[] = {
- 0, 1, 1, 2, 2, 2, 3, 3, 3,
- 1, 1, 1, 1, 1, 1
- };
-
- static char *error_messages[] = {
- "Syntax",
- "Illegal program",
- "Illegal direct",
- "Line number",
- "Wrong type",
- "Divide by zero",
- "Nesting",
- "File not open",
- "File already open",
- "Input"
- };
-
- char sa1[SA_SIZE], sa2[SA_SIZE]; /* string accumulators */
- struct line_record *pgm_start, *runptr; /* Line tracking pointers */
-
- int num_vars[NUM_VAR] = { 0 }; /* Numeric variables */
- char *char_vars[NUM_VAR] = { 0 }; /* Character variables */
-
- FILE *files[10]={0}, *filein, *fileout; /* File unit numbers */
-
- int savjmp[3]; /* Save area for set/longjmp */
-
- /* Misc. global variables */
- char *cmdptr, buffer[BUFFER_SIZE], mode, expr_type, nest;
- unsigned line, ctl_ptr = 0, ctl_stk[100];
-
- /* test for end of expression */
- isend(c)
- char c;
- {
- if((c >= (0xff80+SEC)) && (c < (0xff80+OPS)))
- return(1);
- return (c == '\0') || (c == ':') || (c == ')') || (c == ',');
- }
-
- /* test for end of statement */
- islend(c)
- char c;
- {
- return (c == '\0') || (c == ':');
- }
-
- /* test for terminator character */
- isterm(c)
- char c;
- {
- return (c == ' ') || (c == '\t');
- }
-
- /* advance to next non-blank */
- char skip_blank()
- {
- while(isterm(*cmdptr))
- ++cmdptr;
- return *cmdptr;
- }
-
- /* advance to., return and skip next non blank */
- char skip_next()
- {
- char c;
-
- while(isterm(c=*cmdptr))
- ++cmdptr;
- if(c)
- ++cmdptr;
- return c;
- }
-
- /* translate to special codes */
- translate()
- {
- unsigned value;
- char *ptr, c;
-
- cmdptr = ptr = buffer;
-
- while(c = *cmdptr) {
- if(value = lookup(reserved_words))
- *ptr++ = value + 0x80;
- else {
- *ptr++ = c;
- ++cmdptr;
- if(c == '"') { /* double quote */
- while((c = *cmdptr) && (c != '"')) {
- ++cmdptr;
- *ptr++ = c; }
- *ptr++ = *cmdptr++; } } }
- *ptr = 0;
- cmdptr = buffer;
- }
-
- /* prompt for and get a line from standard input */
- char get_line(prompt)
- char *prompt;
- {
- fputs(prompt, stdout);
- fgets(buffer, BUFFER_SIZE, stdin);
- translate();
- return skip_blank();
- }
-
- /* get a number from the input buffer */
- get_num()
- {
- unsigned value;
- char c;
-
- value = 0;
- while(isdigit(c=*cmdptr)) {
- ++cmdptr;
- value = (value * 10) + (c - '0'); }
- return value;
- }
-
- /* lookup up word from command line in table */
- lookup(table)
- char *table[];
- {
- unsigned i;
- char *cptr, *optr;
-
- optr = cmdptr;
- for(i=0; cptr = table[i]; ++i) {
- while((*cptr) && (*cptr == toupper(*cmdptr))) {
- ++cptr;
- ++cmdptr; }
- if(!*cptr) {
- skip_blank();
- return i+1; }
- cmdptr = optr; }
- return 0;
- }
-
- /* main program */
- main()
- {
- unsigned value;
- char cmd;
-
- pgm_start = 0;
- setjmp(savjmp);
- for(;;) { /* main command loop */
- mode = ctl_ptr = 0;
- while(!get_line("Ready\n")); /* insure we get command */
- if(0 > (cmd = skip_blank())) {
- ++cmdptr;
- execute(cmd); }
- else { /* not a known command */
- if(isdigit(*cmdptr)) { /* editing... */
- value = get_num(); /* get line number */
- delete_line(value); /* delete the old */
- if(skip_blank())
- insert_line(value); } /* insert the new */
- else
- execute(1); } } /* assume let */
- }
-
- /* delete a line from the program */
- delete_line(lino)
- unsigned lino;
- {
- struct line_record *cptr, *bptr;
-
- if(!(cptr = pgm_start)) /* no lines in pgm */
- return;
- do {
- if(lino == cptr->Lnumber) { /* we have line to delete */
- if(cptr == pgm_start) { /* first line in pgm */
- pgm_start = cptr->Llink;
- return; }
- else {
- bptr->Llink = cptr->Llink; /* skip it in linked list */
- free(cptr); } } /* let it go */
- bptr = cptr; }
- while(cptr = cptr->Llink);
- }
-
- /* Insert a line into the program */
- insert_line(lino)
- unsigned lino;
- {
- unsigned i;
- struct line_record *cptr, *bptr, *optr;
- char *ptr;
-
- ptr = cmdptr;
- for(i=5; *ptr; ++i)
- ++ptr;
- if(!(bptr = malloc(i)))
- fputs("No memory\n", stdout);
- else {
- bptr->Lnumber = lino;
- for(i=0; *cmdptr; ++i)
- bptr->Ltext[i] = *cmdptr++;
- bptr->Ltext[i] = 0;
- if((!(cptr = pgm_start)) || (lino < cptr->Lnumber)) { /* at start */
- bptr->Llink = pgm_start;
- pgm_start = bptr; }
- else { /* inserting into main part of pgm */
- for(;;) {
- optr = cptr;
- if((!(cptr = cptr->Llink)) || (lino < cptr->Lnumber)) {
- bptr->Llink = optr->Llink;
- optr->Llink = bptr;
- break; } } } }
- }
-
- /* execute commands */
- execute(cmd)
- char cmd;
- {
- unsigned i,j, k;
- int ii, jj;
- struct line_record *cptr;
- char c;
-
- switch(cmd & 127) {
- case 1 : /* LET */
- i = get_var();
- j = expr_type;
- if(skip_next() != (0xff88+OPS))
- error(0);
- k = eval();
- if(j != expr_type)
- error(0);
- if(!expr_type) /* numeric assignment */
- num_vars[i] = k;
- else { /* character assignment */
- if(char_vars[i])
- free(char_vars[i]);
- if(*sa1)
- strcpy((char_vars[i] = malloc(strlen(sa1)+1)), sa1);
- else
- char_vars[i] = 0; }
- break;
- case 2 : /* EXIT */
- exit(0);
- case 3 : /* LIST */
- chk_file(1);
- if(!isdigit(skip_blank())) {
- i=0; j=-1; }
- else {
- i = get_num();
- if(','==skip_next()) {
- if(isdigit(skip_blank()))
- j=get_num();
- else
- j = -1; }
- else
- j=i; }
- disp_pgm(fileout,i,j);
- break;
- case 4 : /* NEW */
- for(cptr = pgm_start; cptr; cptr = cptr->Llink)
- free(cptr);
- pgm_start = 0;
- longjmp(savjmp, 1);
- case 5 : /* RUN */
- if(mode) error(1);
- if(isend(skip_blank()))
- runptr = pgm_start;
- else
- runptr = find_line(eval_num());
- --mode; /* indicate running */
- clear_vars();
- newline:
- while(runptr) {
- cmdptr = runptr->Ltext;
- line = runptr->Lnumber;
- do {
- if((cmd = skip_blank()) < 0) {
- ++cmdptr;
- if(i=execute(cmd)) {
- runptr = i;
- goto newline; } }
- else
- execute(1); }
- while((c = skip_next()) == ':');
- if(c)
- error(0);
- runptr = runptr->Llink; }
- mode = 0;
- break;
- case 6 : /* CLEAR */
- clear_vars();
- break;
- case 7 : /* GOSUB */
- ctl_stk[ctl_ptr++] = runptr;
- ctl_stk[ctl_ptr++] = cmdptr;
- ctl_stk[ctl_ptr++] = GOSUB;
- case 8 : /* GOTO */
- pgm_only();
- return find_line(eval_num());
- case 9 : /* RETURN */
- pgm_only();
- if(ctl_stk[--ctl_ptr] != GOSUB)
- error(6);
- cmdptr = ctl_stk[--ctl_ptr];
- runptr = ctl_stk[--ctl_ptr];
- line = runptr->Lnumber;
- skip_stmt();
- break;
- case 10 : /* PRINT */
- chk_file(1);
- j = 0;
- --cmdptr;
- do {
- ++cmdptr;
- if(islend(skip_blank()))
- --j;
- else {
- i = eval();
- if(!expr_type) {
- num_string(i, sa1);
- putc(' ',fileout); }
- fputs(sa1, fileout); } }
- while(skip_blank() == ',');
- if(!j)
- putc('\n', fileout);
- break;
- case 11 : /* FOR */
- pgm_only();
- ii = 1; /* default step value */
- i = get_var();
- if(expr_type) error(0);
- if(skip_next() != (0xff88+OPS)) error(0);
- num_vars[i] = eval();
- if(expr_type) error(0);
- if(skip_next() != (0xff80+SEC)) error(0);
- jj = eval();
- if(skip_blank() == (0xff81+SEC)) {
- ++cmdptr;
- ii = eval(); }
- skip_stmt();
- ctl_stk[ctl_ptr++] = runptr; /* line */
- ctl_stk[ctl_ptr++] = cmdptr; /* command pointer */
- ctl_stk[ctl_ptr++] = ii; /* step value */
- ctl_stk[ctl_ptr++] = jj; /* limit value */
- ctl_stk[ctl_ptr++] = i; /* variable number */
- ctl_stk[ctl_ptr++] = FOR;
- break;
- case 12 : /* NEXT */
- pgm_only();
- if(ctl_stk[ctl_ptr-1] != FOR)
- error(6);
- i = ctl_stk[ctl_ptr-2];
- if(!islend(skip_blank()))
- if(get_var() != i) error(6);
- jj = ctl_stk[ctl_ptr-3]; /* get limit */
- ii = ctl_stk[ctl_ptr-4]; /* get step */
- num_vars[i] += ii;
- if((ii < 0) ? num_vars[i] >= jj : num_vars[i] <= jj) {
- cmdptr = ctl_stk[ctl_ptr-5];
- runptr = ctl_stk[ctl_ptr-6];
- line = runptr->Lnumber; }
- else
- ctl_ptr -= 6;
- break;
- case 13 : /* IF */
- i = eval_num();
- if(skip_next() != (0xff82+SEC))
- error(0);
- if(i) {
- if(isdigit(cmd = skip_blank()))
- return find_line(eval_num());
- else if(cmd < 0) {
- ++cmdptr;
- return execute(cmd); }
- else
- execute(1); }
- else
- skip_stmt();
- break;
- case 14 : /* LIF */
- i = eval_num();
- if(skip_next() != (0xff82+SEC))
- error(0);
- if(i) {
- if((cmd = skip_blank()) < 0) {
- ++cmdptr;
- return execute(cmd); }
- else
- execute(1);
- break; }
- case 15 : /* REM */
- if(mode) {
- if(cptr = runptr->Llink)
- return cptr;
- longjmp(savjmp, 1); }
- break;
- case 16 : /* STOP */
- pgm_only();
- printf("STOP in line %u\n",line);
- case 17 : /* END */
- pgm_only();
- longjmp(savjmp, 1);
- case 18 : /* INPUT */
- ii = chk_file(1);
- if(skip_blank() == '"') { /* special prompt */
- eval();
- if(skip_next() != ',') error(0); }
- else
- strcpy(sa1, "? ");
- i = get_var();
- cptr = cmdptr;
- input: if(ii == -1)
- fputs(sa1, stdout);
- cmdptr = fgets(buffer,BUFFER_SIZE,filein);
- if(expr_type) {
- if(char_vars[i]) free(char_vars[i]);
- strcpy((char_vars[i] = malloc(strlen(buffer)+1)), buffer); }
- else {
- k = 0;
- if(skip_blank() == '-') {
- ++cmdptr;
- --k; }
- if(!isdigit(*cmdptr)) {
- if(ii != -1) error(9);
- fputs("Input error\n",stdout);
- goto input; }
- j = get_num();
- if(k)
- j= 0 - j;
- num_vars[i] = j; }
- cmdptr = cptr;
- break;
- case 19 : /* OPEN */
- if(skip_blank() != '#') error(0);
- if(files[i = chk_file(0)]) error(8);
- eval_char();
- strcpy(buffer,sa1);
- if(skip_next() != ',') error(0);
- eval_char();
- files[i] = fopen(buffer,sa1);
- break;
- case 20 : /* CLOSE */
- if((i = chk_file(1)) == -1) error(0);
- if(!filein) error(8);
- fclose(files[i]);
- files[i] = 0;
- break;
- default : /* unknown */
- error(0); }
- return 0;
- }
-
- /* test for file operator, and set up pointers */
- chk_file(flag)
- char flag;
- {
- unsigned i;
-
- i = -1;
- if(skip_blank() == '#') {
- ++cmdptr;
- if(9 < (i = eval_num())) error(7);
- if(skip_blank() == ',')
- ++cmdptr;
- filein = fileout = files[i];
- if(flag && (!filein))
- error(7); }
- else {
- filein = stdin;
- fileout = stdout; }
- return i;
- }
-
- /* display program listing */
- disp_pgm(fp, i, j)
- FILE *fp;
- unsigned i,j;
- {
- unsigned k;
- struct line_record *cptr;
- char c;
-
- for(cptr = pgm_start; cptr; cptr = cptr->Llink) {
- k = cptr->Lnumber;
- if((k >= i) && (k <= j)) {
- fprintf(fp,"%u ",k);
- for(k=0; c = cptr->Ltext[k]; ++k)
- if(c < 0) {
- c = c & 127;
- fputs(reserved_words[c - 1], fp);
- if(c < OPS)
- putc(' ',fp); }
- else
- putc(c,fp);
- putc('\n', fp); } }
- }
-
- /* test for program only, and error if so */
- pgm_only()
- {
- if(!mode) error(2);
- }
-
- /* skip rest of statement */
- skip_stmt()
- {
- char c;
-
- while((c=*cmdptr) && (c != ':')) {
- ++cmdptr;
- if(c == '"') {
- while((c=*cmdptr) && (c != '"'))
- ++cmdptr;
- if(c) ++cmdptr; } }
- }
-
- /* locate given line in source */
- find_line(line)
- unsigned line;
- {
- struct line_record *cptr;
-
- for(cptr = pgm_start; cptr; cptr = cptr->Llink)
- if(cptr->Lnumber == line)
- return cptr;
- error(3);
- }
-
- /* dislay error message */
- error(en)
- unsigned en;
- {
- printf("%s error", error_messages[en]);
- if(mode)
- printf(" in line %u",line);
- putc('\n',stdout);
- longjmp(savjmp, 1);
- }
-
- /* evaluate number only */
- eval_num()
- {
- unsigned value;
-
- value = eval();
- if(expr_type)
- error(4);
- return value;
- }
-
- /* evaluate character only */
- eval_char()
- {
- eval();
- if(!expr_type)
- error(4);
- }
-
- /* evaluate an expression */
- eval()
- {
- unsigned value;
-
- nest = 0;
- value = eval_sub();
- if(nest != 1) error(0);
- return value;
- }
-
- /* evaluate a sub expression */
- eval_sub()
- {
- unsigned value, nstack[10], nptr, optr;
- char c, ostack[10];
-
- ++nest; /* indicate we went down */
-
- /* establish first entry on number and operator stacks */
- ostack[optr = nptr = 0] = 0; /* add zero to init */
-
- nstack[++nptr] = get_value(); /* get next value */
- /* string operations */
- if(expr_type) { /* string operations */
- while(!isend(c = skip_blank())) {
- ++cmdptr;
- c = (c & 0x7f) - (OPS-1);
- get_char_value(sa2);
- if(c == 1)
- strcat(sa1, sa2);
- else {
- if(c == 9)
- value = (0 == strcmp(sa1, sa2));
- else if(c == 10)
- value = (1 != strcmp(sa1, sa2));
- else
- error(0);
- nstack[nptr] = value;
- expr_type = 0; } } }
-
- /* numeric operations */
- else {
- while(!isend(c = skip_blank())) {
- ++cmdptr;
- c = (c & 0x7f) - (OPS-1);
- if(priority[c] <= priority[ostack[optr]]) { /* execute operand */
- value = nstack[nptr--];
- nstack[nptr] = do_arith(ostack[optr--], nstack[nptr], value); }
- nstack[++nptr] = get_value(); /* stack next operand */
- if(expr_type) error(0);
- ostack[++optr] = c; }
- while(optr) { /* clean up all pending operations */
- value = nstack[nptr--];
- nstack[nptr] = do_arith(ostack[optr--], nstack[nptr], value); } }
- if(c == ')') {
- --nest;
- ++cmdptr; }
- return nstack[nptr];
- }
-
- /* get a value element for an expression */
- get_value()
- {
- unsigned value;
- char c, *ptr;
-
- expr_type = 0;
- if(isdigit(c = skip_blank()))
- value = get_num();
- else {
- ++cmdptr;
- if(c == '(') /* nesting */
- value = eval_sub();
- else if(c == '!') /* not */
- value = ~get_value();
- else if(c == (0xff81+OPS)) /* negative */
- value = 0 - get_value();
- else if(c == (0xff80+NOPS)) { /* ASC */
- eval_sub();
- if(!expr_type) error(4);
- value = 255 & *sa1;
- expr_type = 0; }
- else if(c == (0xff81+NOPS)) { /* ABS */
- value = eval_sub();
- if(expr_type) error(4);
- if(value > 32767) value = 0- value; }
- else { /* test for character expression */
- --cmdptr;
- if(isalpha(c)) { /* variable */
- value = get_var();
- if(expr_type) { /* char */
- if(ptr = char_vars[value])
- strcpy(sa1, ptr);
- else
- strcpy(sa1, ""); }
- else
- value = num_vars[value]; }
- else
- get_char_value(sa1); } }
- return value;
- }
-
- /* get character value */
- get_char_value(ptr)
- char *ptr;
- {
- unsigned i;
- char c, *st;
-
- if((c = skip_next()) == '"') { /* character value */
- while((c = *cmdptr++) != '"') {
- if(!c) error(0);
- *ptr++ = c; }
- *ptr = 0; }
- else if(isalpha(c)) { /* variable */
- --cmdptr;
- i = get_var();
- if(!expr_type)
- error(0);
- if(st = char_vars[i])
- strcpy(ptr,st);
- else
- strcpy(ptr,""); }
- else if(c == 0xff80+SOPS) { /* CHR$ */
- *ptr++ = eval_sub();
- if(expr_type)
- error(4);
- *ptr = 0; }
- else if(c == 0xff81+SOPS) { /* STR$ */
- num_string(eval_sub(), ptr);
- if(expr_type)
- error(4); }
- else
- error(0);
- expr_type = 1;
- }
-
- /* perform an arithmetic operation */
- do_arith(opr, op1, op2)
- char opr;
- unsigned op1, op2;
- {
- unsigned value;
-
- switch(opr) {
- case 1 : /* addition */
- value = op1 + op2;
- break;
- case 2 : /* subtraction */
- value = op1 - op2;
- break;
- case 3 : /* multiplication */
- value = op1 * op2;
- break;
- case 4 : /* division */
- value = op1 / op2;
- break;
- case 5 : /* modulus */
- value = op1 % op2;
- break;
- case 6 : /* logincal and */
- value = op1 & op2;
- break;
- case 7 : /* logical or */
- value = op1 | op2;
- break;
- case 8 : /* exclusive or */
- value = op1 ^ op2;
- break;
- case 9 : /* equals */
- value = op1 == op2;
- break;
- case 10 : /* not-equals */
- value = op1 != op2;
- break;
- case 11 : /* less than or equal to */
- value = op1 <= op2;
- break;
- case 12 : /* less than */
- value = op1 < op2;
- break;
- case 13 : /* greater than or equal to */
- value = op1 >= op2;
- break;
- case 14 : /* greater than */
- value = op1 > op2;
- break;
- default:
- error(0); }
- return value;
- }
-
- /* convert a number to a string, and place in memory */
- num_string(value, ptr)
- unsigned value;
- char *ptr;
- {
- char cstack[5], cptr;
-
- cptr = 0;
-
- if(value > 32767) {
- *ptr++ = '-';
- value = -value; }
- do
- cstack[cptr++] = (value % 10) + '0';
- while(value /= 10);
- while(cptr)
- *ptr++ = cstack[--cptr];
- *ptr = 0;
- }
-
- /* clear all variables to zero */
- clear_vars()
- {
- unsigned i;
- char *ptr;
-
- for(i=0; i < NUM_VAR; ++i) {
- num_vars[i] = 0;
- if(ptr = char_vars[i]) {
- free(ptr);
- char_vars[i] = 0; } }
- }
-
- /* get index for variable */
- get_var()
- {
- unsigned index;
- char c;
-
- if(!isalpha(c = skip_next()))
- error(0);
- index = (c - 'A') & 0x1f;
- if(isdigit(c = *cmdptr)) {
- index += (c - '0') * 26;
- c = *++cmdptr; }
- if(c == '$') {
- ++cmdptr;
- expr_type = 1; }
- else
- expr_type = 0;
-
- return index;
- }
-